package top.zigaoliang.javaapi;

import com.sun.org.glassfish.gmbal.Description;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

/**
 * @ClassName TestJavaApi
 * @Author hanlin
 * @Date 2019/8/16 16:04
 * 测试zk的基本操作 增删改查
 **/
public class TestJavaApi {
    public static final String SERVER = "192.168.100.11:2181";
    public static final int SERVER_TIMEOUT = 30000;
    public static CountDownLatch cdl = new CountDownLatch(1);
    public static ZooKeeper zk = null;

    /**
     * @Author hanlin
     * @Date 2019/8/16 16:09
     * @Description 创建连接
     * @param
     * @return void
     **/
    public static void createSession() throws IOException, InterruptedException {
        zk = new ZooKeeper(SERVER, SERVER_TIMEOUT, new Watcher() {
            public void process(WatchedEvent watchedEvent) {
                System.out.println("连接成功！");
                cdl.countDown();
            }
        });
        cdl.await();
    }

    /**
     * @Author hanlin
     * @Date 2019/8/16 16:11
     * @Description 关闭连接
     * @param
     * @return void
     **/
    public static void releaseSession(){
        if(null != zk){
            try {
                zk.close();
            } catch (InterruptedException e) {
                System.out.println("关闭连接失败！");
                e.printStackTrace();
            }
        }
    }

    /**
     * @Author hanlin
     * @Date 2019/8/16 16:23
     * @Description 在zk中创建一个节点
     * @param path 路径
     * @param data 节点上的数据，节点上的数据只有一份，后面添加的会覆盖前面的数据
     * @return void
     **/
    public static void createNode(String path,String data){
        try {
            String node = zk.create(path,data.getBytes(),
                    ZooDefs.Ids.OPEN_ACL_UNSAFE,//节点的权限，当前是所有人都可以访问
                    CreateMode.EPHEMERAL //节点类型 有序 无序 临时 永久 两两组合
            );
            System.out.println("创建节点成功！" + node);
        } catch (KeeperException e) {
            System.out.println("创建节点失败！");
            e.printStackTrace();
        } catch (InterruptedException e) {
            System.out.println("创建节点失败！");
            e.printStackTrace();
        }
    }

    /**
     * @Author hanlin
     * @Date 2019/8/16 16:28
     * @Description 读取zk节点上的数据，数据只有一份
     * @param path 节点路径
     * @return void
     **/
    public static void getData(String path){
        try {
            byte[] data = zk.getData(path,null,null);
            System.out.println("读取数据成功！"+ new String(data));
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * @Author hanlin
     * @Date 2019/8/16 16:32
     * @Description 为节点设置数据
     * @param path 节点路径
     * @param data 要添加的数据，添加的数据会覆盖以前的数据
     * @return void
     **/
    public static void setData(String path,String data){
        try {
            //第三个参数是版本号 －1表示不验证 ，这里使用版本号确认线程安全，确保没在过程中被其它线程修改
            Stat stat = zk.setData(path,data.getBytes(),-1);
            System.out.println("设置数据成功！"+stat);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * @Author hanlin
     * @Date 2019/8/16 16:35
     * @Description 删除一个节点，如果该节点下有子节点，将失败
     * @param path 节点的路径
     * @return void
     **/
    public static void deleteNode(String path){
        try {
            //第二个参数是版本号 －1表示不验证 ，这里使用版本号确认线程安全，确保没在过程中被其它线程修改
            zk.delete(path,-1);
            System.out.println("删除节点成功！");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        String path = "/test";
        String path2 = "/test/t1";
        String data = "tom";
        createSession();
        createNode(path,data);
        createNode(path2,"tom1");
//        setData(path,"tom2"); 报错 NoChildrenForEphemerals   子节点不能是临时的
        getData(path);
        deleteNode(path);
        releaseSession();
    }
}
